package com.magic.framework.exception;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.magic.framework.model.AjaxResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 应用到所有@RequestMapping注解方法，在其执行之前初始化数据绑定器
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {}

    /**
     * 把值绑定到Model中，使全局@RequestMapping可以获取到该值
     * @param model
     */
    @ModelAttribute
    public void addAttributes(Model model) {
        model.addAttribute("author", "magic server");
    }

    /**
     * 所有异常都返回统一的json数据
     * @param ex CustomException
     */
    @ExceptionHandler(value = CustomException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public AjaxResult handleCustomException(CustomException ex) {
        log.error("业务异常:{}", ex.getMsg());
        return AjaxResult.error(ex.getCode(), ex.getMsg());
    }

    @ExceptionHandler(value = {MyCustomException1.class})
    public void onMyException1(){
        // 处理 MyCustomException1 这种异常
    }

    @ExceptionHandler(value = {MyCustomException2.class})
    public void onMyException2(){
        // 处理 MyCustomException2 这种异常
    }

    /**
     * 处理 MethodArgumentNotValidException, BindException 这两种异常
     * 解释：利用 jackson 对请求参数进行校验
     */
    @ExceptionHandler(value= {MethodArgumentNotValidException.class , BindException.class})
    public String onException(Exception e) throws JsonProcessingException {
        BindingResult bindingResult = null;
        if (e instanceof MethodArgumentNotValidException) {
            bindingResult = ((MethodArgumentNotValidException)e).getBindingResult();
        } else if (e instanceof BindException) {
            bindingResult = ((BindException)e).getBindingResult();
        }
        Map<String,String> errorMap = new HashMap<>(16);
        assert bindingResult != null;
        bindingResult.getFieldErrors().forEach((fieldError)->
                errorMap.put(fieldError.getField(),fieldError.getDefaultMessage())
        );
        return objectMapper.writeValueAsString(errorMap);
    }
}